import {Injectable} from '@angular/core';
import {DatePipe} from '@angular/common';
import {Subject} from 'rxjs/Subject';
import {format as utilFormat} from 'util';
import {AppConfig} from '../../config';
import {TagProtocol} from './tag-protocol';
import {HistoryService} from './history.service';
import {IMPushTestService} from './impush-test.service';
import {TagData} from '../../entity/tag-data.model';
import {MatrixData} from '../../entity/matrix-data';
import {FaultData} from '../../entity/fault-data';
import {Tag} from '../../entity/tag.model';
import {InterceptorService} from '../interceptor/interceptor-service';
import {SubstationData} from '../../entity/substation-data';
import {DeviceAlarm} from '../../entity/alarm/alarm.model';

/**
 * 测点数据源服务
 *
 * @export
 * @class DataSourceService
 */
@Injectable()
export class DataSourceService {
  private readonly param = 'tags/subTags';

  private get url(): string {
    return `${AppConfig.APP_RESTFUL}/${this.param}`;
  }

  /**
   * 主题对象数组
   *
   * @private
   * @type {Subject<any>[]}
   * @memberof IMPushService
   */
  private subjectMap: Subject<any>[] = [];
  private push: IMPushTestService;
  public history: HistoryService;
  // 测点协议接口对象
  private protocol: TagProtocol;
  // 测点数据
  private tagDatas: TagData[];

  /**
   * Creates an instance of DataSourceService.
   * @param {IPush} push 实时数据推送服务
   * @param {IHistory} history 历史数据拉取服务
   * @memberof DataSourceService
   */

  constructor(
    // private http: Http,
    private http: InterceptorService,
    private datePipe: DatePipe,
  ) {
    this.push = new IMPushTestService();
    this.history = new HistoryService(this.http, this.datePipe);
    this.protocol = new TagProtocol();
    this.tagDatas = [];
  }

  /**
   * 绑定测点
   *
   * @param {string[]} tagNodes
   * @param {string} tagCode
   * @returns {TagData}
   * @memberof DataSourceService
   */
  public binding(tagNodes: string[], tag: Tag): TagData {
    let code = this.buildTagCode(tagNodes, tag);
    let tagData: TagData = null;
    if (code != '') {
      let index = this.tagDatas.findIndex(o => o.code === code);
      if (index >= 0) {
        tagData = this.tagDatas[index];
      } else {
        tagData = {
          code: code,
          value: 0,
          status: 0,
          time: new Date(),
          tagUnit: tag.tagUnit,
          tagName: tag.tagName,
        };
        this.tagDatas.push(tagData);
      }
    }
    else {
      tagData = {
        code: code,
        value: 0,
        status: 0,
        time: new Date()
      }
    }
    return tagData;
  }

  /**
   * 绑定测点
   *
   * @param {string[]} tagNodes
   * @param {string} tagCode
   * @returns {TagData}
   * @memberof DataSourceService
   */
  public bindingWhithCode(code: string): TagData {
    let tagData: TagData = null;
    if (code !== '') {
      const index = this.tagDatas.findIndex(o => o.code === code);
      if (index >= 0) {
        tagData = this.tagDatas[index];
      } else {
        tagData = {
          code: code,
          value: 0,
          status: 0,
          time: new Date(),
        };
        this.tagDatas.push(tagData);
      }
    } else {
      tagData = {
        code: code,
        value: 0,
        status: 0,
        time: new Date()
      };
    }
    return tagData;
  }

  /**
   * 开始订阅数据
   *
   * @returns {Subject<any>}
   * @memberof DataSourceService
   */
  public begin(): Subject<TagData[]> {
    this.buildTagProtocol();
    let subject: Subject<TagData[]> = new Subject();
    this.subjectMap.push(subject);
    this.push
      .begin(this.protocol)
      .subscribe(
        next => {
          try {
            let nextDatas: TagData[] = [];
            next.forEach(nextData => {
              let data = this.tagDatas.find(o => o.code === nextData.code);
              if (data != null) {
                try {
                  data.value = nextData.value;
                  data.time = nextData.time;
                  data.status = nextData.status;
                  nextDatas.push(nextData);
                } catch (ex) {
                  console.log(ex);
                }
              }

            })
            this.next(subject, nextDatas);

          }
          catch (error) {
            console.log(error);
          }
        },
        error => {
          this.error(subject, error);
        });
    return subject;
  }

  public withHistories(start: Date, end: Date): Subject<{ historyData?: TagData[]; intervalData?: TagData[]; time?: Date }>;
  public withHistories(start: Date, end: Date, interval: number): Subject<{ historyData?: TagData[]; intervalData?: TagData[]; time?: Date }>;
  public withHistories(start: Date, end: Date, interval: { history: number; push: number; }): Subject<{ historyData?: TagData[]; intervalData?: TagData[]; time?: Date }>;
  public withHistories(start: Date, end: Date, interval?: any): Subject<{ historyData?: TagData[]; intervalData?: TagData[]; time?: Date }> {
    this.buildTagProtocol();
    let isFirst = true;
    let subject: Subject<any> = new Subject();
    this.subjectMap.push(subject);
    this.push.withHistories(this.protocol, start, end, interval)
      .subscribe(
        next => {
          if (isFirst) {
            try {
              this.tagDatas.forEach(currTagData => {
                let historyTagDatas = next.filter(historyTagData => historyTagData.code == currTagData.code);
                if (historyTagDatas != null && historyTagDatas.length > 0) {
                  let data = historyTagDatas.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime())[0];
                  currTagData.time = data.time;
                  currTagData.value = data.value;
                  currTagData.status = data.status;
                }
              });
              if (next != null && next.length && next.length > 0) {
                this.next(subject, {historyData: next});
              }
            }
            catch (error) {
              this.error(subject, error);
            }
          }//推送历史数据
          else {
            try {
              if (next != null && next.length && next.length > 0) {
                let nextDatas: TagData[] = [];
                next.forEach(nextData => {
                  let data = this.tagDatas.find(o => o.code === nextData.code);
                  if (data != null) {
                    try {
                      data.value = nextData.value;
                      data.time = nextData.time;
                      data.status = nextData.status;
                    } catch (ex) {
                      console.log(ex);
                    }
                  }
                  nextDatas.push(nextData);
                })
                this.next(subject, {
                  intervalData: nextDatas,
                  time: new Date()
                });

              }
            }
            catch (error) {
              this.error(subject, error);
            }
          }//推送实时数据

          //第一次推送过来的是历史数据
          if (isFirst)
            isFirst = false;
        },
        error => {
          this.error(subject, error);
        });
    return subject;
  }

  /**
   * 订阅风机矩阵数据
   *
   * @param {{tagId: number,farmIds: number[]}} matrix
   * @returns {Subject<any>}
   * @memberof IMPushService
   */
  public matrix(matrix: { tagId: number, farmIds: number[] }): Subject<MatrixData[]> {
    let subject: Subject<MatrixData[]> = new Subject();
    this.subjectMap.push(subject);
    this.push.matrix(matrix).subscribe(
      next => {
        try {
          this.next(subject, next);
        }
        catch (error) {
          this.error(subject, error);
        }
      },
      error => {
        this.error(subject, error);
      });
    return subject;
  }

  public alarmHistory(startTime, endTime, deviceIds: number[]): Subject<FaultData[]> {
    let subject: Subject<FaultData[]> = new Subject();
    this.subjectMap.push(subject);
    this.push.alarmHistory(startTime, endTime, deviceIds).subscribe(next => {
        try {
          this.next(subject, next);
        }
        catch (error) {
          this.error(subject, error);
        }
      },
      error => {
        this.error(subject, error);
      });
    return subject;
  }

  /**
   * 订阅风机报警数据
   *
   * @param {number} userId
   * @memberof DataSourceService
   */
  public alarm(userId: number): Subject<DeviceAlarm[]> {
    let keys: number[] = []
    keys.push(userId)
    let subject: Subject<DeviceAlarm[]> = new Subject();
    this.subjectMap.push(subject);
    this.push.alarm(keys, 1).subscribe(next => {
      try {
        this.next(subject, next)
      } catch (error) {
        this.error(subject, error);
      }
    }, error => {
      this.error(subject, error);
    });
    return subject;
  }

  /**
   * 订阅风机报警数据
   *
   * @param {number} userId
   * @memberof DataSourceService
   */
  public alarmDevice(keys: number[]): Subject<DeviceAlarm[]> {
    let subject: Subject<DeviceAlarm[]> = new Subject();
    this.subjectMap.push(subject);
    this.push.alarm(keys, 2).subscribe(next => {
      try {
        this.next(subject, next)
      } catch (error) {
        this.error(subject, error);
      }
    }, error => {
      this.error(subject, error);
    });
    return subject;
  }

  public sendDeviceAlarmMessage(keys: number[]): void {
    this.push.sendMessage(JSON.stringify({
      keys: keys,
      type: 2
    }));
  }

  /**
   * 订阅升压站数据
   *
   * @param {number} userId
   * @memberof DataSourceService
   */
  public substation(userId: number): Subject<SubstationData[]> {
    let subject: Subject<SubstationData[]> = new Subject();
    this.subjectMap.push(subject);
    this.push.substation(userId).subscribe(next => {
      try {
        this.next(subject, next)
      } catch (error) {
        this.error(subject, error);
      }
    }, error => {
      this.error(subject, error);
    });
    return subject;
  }

  public buildTagCode(tagNodes: string[], tag: Tag): string {
    if (tagNodes == null)
      return '';
    if (tagNodes.length <= 0)
      return '';
    let deviceCode = null;
    if (tagNodes.length > 1) {
      deviceCode = tagNodes[1];
    }
    //去除节点中的空格
    tagNodes.map(o => o = o.trim());
    if (tagNodes.findIndex(o => o === '') >= 0)
      return '';
    if (tag == undefined || tag == null)
      return '';
    //如果是自己定义的计算点（表名加CL，）
    let farmCode = tagNodes[0];
    let farmCodeArray = farmCode.split('.');

    if (tag.tagType == '2') {
      farmCodeArray[0] = `${farmCodeArray[0]}CAL`;
      tagNodes[0] = farmCodeArray.join('.');
    } else if (tag.tagType == '3') {
      farmCodeArray[0] = `${farmCodeArray[0]}1Q`;
      tagNodes[0] = farmCodeArray.join('.');
    } else if (tag.tagType == '4') {
      farmCodeArray[0] = `${farmCodeArray[0]}2Q`;
      tagNodes[0] = farmCodeArray.join('.');
    }

    let code: string = this.protocol.format;
    //格式化编码
    tagNodes.forEach(node => {
      code = utilFormat(code, node);
    });
    code = utilFormat(code, tag.tagCode);

    //将多余部分的连接符去掉
    while (code.endsWith(this.protocol.connector)) {
      code = code.replace(this.protocol.connector, '');
    }
    code = code.substr(0, code.length - 1);
    if (farmCode.indexOf('.MX_') != -1 && (deviceCode != null) && (deviceCode.startsWith('13_') || deviceCode.startsWith('11_')) && tag.tagType != '2') {
      let index = code.lastIndexOf('_');
      code = code.substring(0, index) + code.substring(index + 1, code.length)
    }
    return code;
  }

  /**
   public buildTagCode(tagNodes: string[], tag: Tag):any {
    let farmCode = null;
    let deviceCode= null;
    if(tagNodes==null){ return ""}
    if (tag == undefined || tag == null) return '';

    if (tagNodes.length <= 0) return '';
        farmCode = tagNodes[0];
    if(tagNodes.length > 1){  deviceCode = tagNodes[1];}

    let tagCode = tag.tagCode;
    let tagType = tag.tagType;
    // let resqustUrl = `${this.url}/cirCuits`;
    let resqustUrl = `${this.url}/farmCode/${farmCode}/deviceCode/${deviceCode}/tagCode/${tagCode}/tagType/${tagType}`;
    // http://192.168.15.25:8585/webapi/v1/subTags/farmCode/MM.MX_MM_1/deviceCode/001/tagCode/Communication/tagType/3
    let result = this.fn(farmCode,deviceCode,tagCode,tagType);
    return result;
    // this.http.get(resqustUrl)
    //     .toPromise()
    //     .then(response => {
    //         return response.data
    //     })
    //     .catch(this.handleError);
}

   private fn(farmCode,deviceCode,tagCode,tagType){
        let resqustUrl = `${this.url}/farmCode/${farmCode}/deviceCode/${deviceCode}/tagCode/${tagCode}/tagType/${tagType}`;
        this.http.get(resqustUrl)
        .toPromise()
        .then(response => {
            return response.data
        })
        .catch(this.handleError);
    }




   private handleError(error: any): Promise<any> {
        return Promise.reject(error.message || error);
    }
   */

  /**
   * 构建测点协议
   *
   * @private
   * @memberof DataSourceService
   */
  private buildTagProtocol() {
    this.protocol.tagArrary = this.tagDatas.map(o => o.code);
  }

  private error(subject: Subject<any>, error: Error) {
    if (subject != null && !subject.closed && !subject.isStopped) {
      console.log('实时数据服务' + error);
      subject.error(error);
    }
  }

  private next(subject: Subject<any>, data: any) {
    if (subject != null && !subject.closed && !subject.isStopped) {
      subject.next(data);
    }
  }

  /**
   * 释放资源
   *
   * @memberof DataSourceService
   */
  public dispose() {
    this.history.dispose();
    this.push.close();
    if (this.subjectMap) {
      this.subjectMap.forEach(map => {
        map.unsubscribe();
        map = null;
      });
      this.subjectMap = null;
    }

  }


}


// WEBPACK FOOTER //
// ./src/app/service/data-source/data-source.service.ts
